package tool

import (
	"asocrawler/conf"
	"asocrawler/db"
	"errors"
	"io/ioutil"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/dop251/goja"

	"github.com/tebeka/selenium"
)

const (
	QiMai_Login          = "https://www.qimai.cn/account/signin"
	QiMai_Login_UserName = "13281260713"
	QiMai_Login_Password = "cxh5830743"

	QiMai_Origin    = "https://www.qimai.cn"
	QiMai_Referer   = "https://www.qimai.cn/rank"
	QiMai_UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"

	QiMai_Detail     = "https://www.qimai.cn/andapp/baseinfo/appid/%d/market/%d"
	QiMai_Ios_Detail = "https://www.qimai.cn/app/baseinfo/appid/%d/country/cn"

	QiMai_Android_Detail_Api = "https://api.qimai.cn/andapp/detail"
	QiMai_Ios_Detail_Api     = "https://api.qimai.cn/app/appinfo"

	QiMai_Analysis_File_Path = "./doc/getQiMaiAnalysis.js"
)

var getAnalysisJsStr = ""
var QiMai_Cookie = ""

func init() {

	if conf.Conf.QiMaiCollectMode == "api" {
		data, err := ioutil.ReadFile(QiMai_Analysis_File_Path)
		if err != nil {
			log.Println("ioutil.ReadFile getQiMaiAnalysis.js err=", err)
			return
		}
		getAnalysisJsStr = string(data)
	}

}

//生成 analysis参数
func GetAnalysisParams(url, params string) (a string, err error) {
	//生成 analysis 密钥参数
	var jsStr = getAnalysisJsStr
	jsStr = strings.Replace(jsStr, "{url}", url, -1)
	jsStr = strings.Replace(jsStr, "{params}", params, -1)

	vm := goja.New()
	_, err = vm.RunString(jsStr)
	if err != nil {
		log.Println(" vm.Run err:", err.Error())
		return
	}
	analysisP := vm.Get("result")
	return analysisP.String(), err
}

// 获取并设置七麦 cookie
func SetQiMaiCookie() (err error) {
	log.Println("开始获取七麦网站cookie...")
	wd, err := OpenHeadLessWebDriver()
	if err != nil {
		log.Println("创建无头浏览器对象失败，err= ", err)
		return err
	}
	//关闭一个webDriver会对应关闭一个chrome窗口
	//但是不会导致seleniumServer关闭
	defer func() {
		wd.Quit()        // 关闭浏览器
		PutBrowserPool() // 放回池子
	}()
	if err = wd.Get(QiMai_Origin); err != nil {
		log.Println("打开七麦首页失败!,err=", err)
		return err
	}
	time.Sleep(1 * time.Second)
	// 判断是否打开了网站
	for {
		cookieIn, err := wd.ExecuteScript("return document.cookie", nil)
		if err != nil {
			log.Println("获取七麦cookie失败!,err=", err)
			return err
		}
		cookie, flag := cookieIn.(string)
		if flag {
			QiMai_Cookie = cookie
			log.Println("已获取到七麦cookie!")
			break
		}
		time.Sleep(1 * time.Second)
	}

	return
}

// 登录后设置七麦cookie
func SetQiMaiCookieByLogin() (err error) {
	log.Println("开始获取七麦网站cookie...")
	wd, err := OpenHeadLessWebDriver()
	if err != nil {
		log.Println("创建无头浏览器对象失败，err= ", err)
		return err
	}
	//关闭一个webDriver会对应关闭一个chrome窗口
	//但是不会导致seleniumServer关闭
	defer func() {
		wd.Quit()        // 关闭浏览器
		PutBrowserPool() // 放回池子
	}()
	if err = wd.Get(QiMai_Login); err != nil {
		log.Println("打开七麦登录页失败!,err=", err)
		return err
	}
	time.Sleep(1 * time.Second)

	tTimes := 0
	for {
		// 30秒未打开，强制退出
		if tTimes == 30 {
			return errors.New("30秒未打开七麦首页，强制退出")
		}
		title, err := wd.Title()
		if err != nil {
			return err
		}

		if strings.Contains(title, "七麦数据") {
			log.Println("打开首页成功!")
			break
		}
		time.Sleep(1 * time.Second)
		tTimes++
	}

	// 执行防反爬脚本
	script := `Object.defineProperty(navigator,'webdriver',{
		get:() => undefined
	})`
	_, err = wd.ExecuteScript(script, nil)
	if err != nil {
		log.Println("注入防反爬脚本失败,err=", err)
		return err
	}
	time.Sleep(1 * time.Second)

	// 点击登录
	_, err = wd.ExecuteScript(`document.querySelector(".sign a").click()`, nil)
	if err != nil {
		log.Println("点击登录按钮失败,err=", err)
		return err
	}
	time.Sleep(1 * time.Second)

	// 判断是否打开了网站
	tTimes1 := 0
	for {
		// 30秒未打开，强制退出
		if tTimes1 == 30 {
			return errors.New("30秒未打开七麦登录页，强制退出")
		}
		title, err := wd.Title()
		if err != nil {
			return err
		}

		if strings.Contains(title, "七麦数据") {
			log.Println("打开登录页成功!")
			break
		}
		time.Sleep(1 * time.Second)
		tTimes1++
	}

	// 输入账号
	log.Println("输入账号...")
	e11, err := wd.FindElement(selenium.ByName, "username")
	if err != nil {
		log.Println("查找账号输入框失败!,err=", err)
		return err
	}
	if err = e11.SendKeys(QiMai_Login_UserName); err != nil {
		log.Println("输入账号失败!,err=", err)
		return err
	}
	time.Sleep(1 * time.Second)

	//输入密码
	log.Println("输入密码...")
	e22, err := wd.FindElement(selenium.ByName, "password")
	if err != nil {
		log.Println("查找密码输入框失败!,err=", err)
		return err
	}
	if err = e22.SendKeys(QiMai_Login_Password); err != nil {
		log.Println("输入密码失败!,err=", err)
		return err
	}

	time.Sleep(1 * time.Second)

	log.Println("点击登录...")
	// 点击登录
	if _, err = wd.ExecuteScript("document.querySelector('.submit').click();", nil); err != nil {
		log.Println("点击登录按钮失败!,err=", err)
		return err
	}

	time.Sleep(1 * time.Second)

	// 判断登录跳转成功
	/* tTimes2 := 0
	for {
		if tTimes2 == 30 {
			return errors.New("登录成功后30秒未跳转到七麦首页，强制退出")
		}
		title, err := wd.ExecuteScript("return document.querySelector('.module-name')", nil)
		if err != nil {
			return err
		}
		contet, _ := wd.ExecuteScript("return document.body.innerText", nil)
		log.Println("contet", contet)
		if title != nil {
			log.Println("跳转首页成功!")
			break
		}
		time.Sleep(1 * time.Second)
		tTimes2++
	} */

	// 获取cookie
	cookieIn, err := wd.ExecuteScript("return document.cookie", nil)
	if err != nil {
		log.Println("获取cookie失败!,err=", err)
		return err
	}
	cookie, flag := cookieIn.(string)
	if flag {
		QiMai_Cookie = cookie
		log.Println("获取七麦cookie成功!")
	}
	return
}

// html文本解析获取数据
func GetQiMaiDataByHtml(url string) (ds []db.AppResultInfo, err error) {
	log.Println("开始获取七麦网站data HTML文本.url=", url)

	wd, err := OpenWebDriver()
	if err != nil {
		log.Println("创建无头浏览器对象失败，err= ", err)
		return
	}

	//关闭一个webDriver会对应关闭一个chrome窗口
	//但是不会导致seleniumServer关闭
	defer func() {
		wd.Quit()        // 关闭浏览器
		PutBrowserPool() // 放回池子
	}()

	if err = wd.Get(url); err != nil {
		log.Println("打开七麦Data页失败!,err=", err)
		return
	}
	time.Sleep(1 * time.Second)

	tTimes := 0
	for {
		// 30秒未打开，强制退出
		if tTimes == 30 {
			err = errors.New("30秒未打开七麦，强制退出")
			return
		}
		title, err := wd.Title()
		if err != nil {
			return ds, err
		}

		if strings.Contains(title, "七麦数据") {
			log.Println("打开Data页成功!")
			break
		}
		time.Sleep(1 * time.Second)
		tTimes++
	}

	time.Sleep(200 * time.Second)

	htmlInterface, err := wd.ExecuteScript("return document.documentElement.innerHTML", nil)
	if err != nil {
		return
	}

	htmlStr, _ := htmlInterface.(string)

	// ioutil.WriteFile("./index.html", []byte(htmlStr), 0777)

	nReader := strings.NewReader(htmlStr)

	// Load the HTML document
	doc, err := goquery.NewDocumentFromReader(nReader)
	if err != nil {
		log.Println("goquery.NewDocumentFromReader error:", err)
		return
	}

	// Find the review items
	trs := doc.Find(".data-table tbody tr")
	trs.Each(func(i int, s *goquery.Selection) {
		if len(trs.Nodes) == i+1 {
			// 最后一行无数据
			return
		}

		// 迭代 表格每一行
		var d db.AppResultInfo

		var appId, appName, company, icon, genre, downloadNum, ranking, appCommentCount string
		var appCommentScore float64

		s.Find("td").Each(func(i2 int, s2 *goquery.Selection) {
			// 迭代 每行每个单元格
			if i2 == 1 {

				icon = s2.Find(".app-info-wrap .icon img").AttrOr("data-src", "")
				appName = s2.Find(".app-info-wrap .app-info .name").Text()
				company = s2.Find(".app-info-wrap .app-info .company").Text()

			} else if i2 == 2 {

				ranking = s2.Find(".rank-total-wrap .total-num a").Text()

			} else if i2 == 3 {

				genre = s2.Find(".index").Text()

			} else if i2 == 4 {

				downloadNum = s2.Find(".index a").Text()

				pStr := s2.Find(".index a").AttrOr("href", "")
				pArr := strings.Split(pStr, "/")
				if len(pArr) > 0 {
					appId = pArr[len(pArr)-1]
				}

			} else if i2 == 5 {

				appCommentScoreStr := s2.Find(".index .big-txt span a").Text()
				appCommentScore, _ = strconv.ParseFloat(appCommentScoreStr, 64)

				pAppCommentCount := s2.Find(".index .small-txt").Text()
				appCommentCount = strings.ReplaceAll(pAppCommentCount, "个评分", "")

			}

			d.AppInfo.AppId = appId
			d.AppInfo.AppName = appName
			d.AppInfo.Icon = icon
			d.AppInfo.AppCommentCount = appCommentCount
			d.AppInfo.AppCommentScore = appCommentScore

			d.DownloadNum = downloadNum
			d.Company.Name = company

			d.RankInfo.Genre = genre
			d.RankInfo.Ranking = ranking

		})

		ds = append(ds, d)
	})

	log.Println("ds", ds)
	return
}

// html文本解析获取数据 IOS
func GetQiMaiDataByIosHtml(url string) (ds []db.IosAppResultInfo, err error) {
	log.Println("开始获取七麦网站data HTML文本.url=", url)

	wd, err := OpenWebDriver()
	if err != nil {
		log.Println("创建无头浏览器对象失败，err= ", err)
		return
	}

	//关闭一个webDriver会对应关闭一个chrome窗口
	//但是不会导致seleniumServer关闭
	defer func() {
		wd.Quit()        // 关闭浏览器
		PutBrowserPool() // 放回池子
	}()

	if err = wd.Get(url); err != nil {
		log.Println("打开七麦Data页失败!,err=", err)
		return
	}
	time.Sleep(1 * time.Second)

	tTimes := 0
	for {
		// 30秒未打开，强制退出
		if tTimes == 30 {
			err = errors.New("30秒未打开七麦，强制退出")
			return
		}
		title, err := wd.Title()
		if err != nil {
			return ds, err
		}

		if strings.Contains(title, "七麦数据") {
			log.Println("打开Data页成功!")
			break
		}
		time.Sleep(1 * time.Second)
		tTimes++
	}

	time.Sleep(2 * time.Second)

	htmlInterface, err := wd.ExecuteScript("return document.documentElement.innerHTML", nil)
	if err != nil {
		return
	}

	htmlStr, _ := htmlInterface.(string)

	// ioutil.WriteFile("./index.html", []byte(htmlStr), 0777)

	nReader := strings.NewReader(htmlStr)

	// Load the HTML document
	doc, err := goquery.NewDocumentFromReader(nReader)
	if err != nil {
		log.Println("goquery.NewDocumentFromReader error:", err)
		return
	}

	// Find the review items
	trs := doc.Find(".data-table tbody tr")
	trs.Each(func(i int, s *goquery.Selection) {
		if len(trs.Nodes) == i+1 {
			// 最后一行无数据
			return
		}

		// 迭代 表格每一行
		var d db.IosAppResultInfo

		var appId, appName, company, icon, genre, ranking, appCommentCount string
		var appCommentScore float64

		s.Find("td").Each(func(i2 int, s2 *goquery.Selection) {
			// 迭代 每行每个单元格
			if i2 == 1 {

				appIdStr := s2.Find(".app-info-wrap .icon").AttrOr("href", "")
				pStr := strings.ReplaceAll(appIdStr, "/country/cn", "")
				pArr := strings.Split(pStr, "/")
				if len(pArr) >= 4 {
					appId = pArr[len(pArr)-1]
				}

				icon = s2.Find(".app-info-wrap .icon img").AttrOr("data-src", "")
				appName = s2.Find(".app-info-wrap .app-info .app-name").Text()
				company = s2.Find(".app-info-wrap .app-info .company").Text()

			} else if i2 == 4 {

				genre = s2.Find(".rank-wrap .rank-box .category").Text()
				ranking = s2.Find(".rank-wrap .rank-box .num a").Text()

			} else if i2 == 6 {

				appCommentScoreStr := s2.Find(".comment-rating a").Text()
				appCommentScoreStr2 := sanitizeText(appCommentScoreStr)

				appCommentScore, _ = strconv.ParseFloat(appCommentScoreStr2, 64)

				pAppCommentCount := s2.Find(".comment-num a").Text()
				appCommentCount = strings.ReplaceAll(pAppCommentCount, "个评分", "")

			}

			d.AppInfo.AppId = sanitizeText(appId)
			d.AppInfo.AppName = sanitizeText(appName)
			d.AppInfo.Icon = sanitizeText(icon)
			d.AppInfo.AppCommentCount = sanitizeText(appCommentCount)
			d.AppInfo.AppCommentScore = appCommentScore

			d.AppInfo.Publisher = sanitizeText(company)
			d.AppInfo.Genre = sanitizeText(genre)
			d.Index = sanitizeText(ranking)

		})

		ds = append(ds, d)
	})

	log.Println("ds", ds)
	return
}

func sanitizeText(t string) string {
	t1 := strings.Replace(t, "\n", "", -1)
	t2 := strings.Replace(t1, " ", "", -1)
	return t2
}
